﻿using System.Collections;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using Noria.Web.MyMSDN.Models;

namespace Noria.Web.MyMSDN.Workers
{
    internal class MsdnFamilyWorker
    {
        private static readonly log4net.ILog slog = log4net.LogManager.GetLogger("Noria.Spider");
        private static readonly log4net.ILog alog = log4net.LogManager.GetLogger("Noria.Audit");

        private readonly string url;

        public MsdnFamilyWorker(string url)
        {
            this.url = url;
        }

        public void RetrieveFamilyListByCategory(IStatistics stat, AsyncWaiter waiter, Category cat)
        {
            dynamic famArray = HttpBot.RequestJArray(stat, string.Format(url, cat.CategoryId));

            // convert
            cat.Families = new List<Family>();
            foreach (dynamic jFamily in (IEnumerable)famArray)
            {
                var family = new Family
                {
                    FamilyId = (long)jFamily.ProductFamilyId,
                    Name = (string)jFamily.Title,
                    CategoryId = cat.CategoryId
                };
                cat.Families.Add(family);
            }

            // log
            slog.InfoFormat("MSDN Families of Category ({0}) retrieved, len={1}", cat.Name, cat.Families.Count);
            foreach (var family in cat.Families)
            {
                slog.DebugFormat("Family -> Name: {0}, Id: {1}.",
                                 family.Name, family.FamilyId);
            }
        }

        public void Save(IStatistics stat, IEnumerable<Family> families)
        {
            // diff with db, update if necessary
            using (var db = new MmContext())
            {
                // get all dbFamilies
                var dbFamilies = db.Families.ToArray();

                MergeFamily(stat, families, dbFamilies, db.Families);

                int ret = db.SaveChanges();
                alog.InfoFormat("Family updated, count={0}", ret);
            }
        }

        private void MergeFamily(IStatistics stat, IEnumerable<Family> memory, IEnumerable<Family> db, DbSet<Family> context)
        {
            foreach (var family in memory)
            {
                var dbFamily = db.FirstOrDefault(p => p.FamilyId == family.FamilyId);
                if (dbFamily != null)
                {
                    bool updated = false;

                    if (!dbFamily.Enabled)
                    {
                        // update
                        dbFamily.Enabled = true;
                        updated = true;
                    }

                    if (dbFamily.CategoryId != family.CategoryId)
                    {
                        // update
                        dbFamily.CategoryId = family.CategoryId;
                        updated = true;
                    }

                    if (dbFamily.Name != family.Name)
                    {
                        // update
                        dbFamily.Name = family.Name;
                        updated = true;
                    }

                    if (updated)
                    {
                        stat.AddUpdated();
                    }
                }
                else
                {
                    // insert
                    family.Enabled = true;
                    context.Add(family);
                    stat.AddInserted();
                }
            }

            foreach (var dbFamily in db)
            {
                if (memory.All(p => p.FamilyId != dbFamily.FamilyId))
                {
                    // delete
                    if (dbFamily.Enabled)
                    {
                        dbFamily.Enabled = false;
                        stat.AddDeleted();
                    }
                }
            }
        }


    }
}